/*
 *
 * Copyright (c) 2006 Sam Collett (http://www.texotela.co.uk)
 * Licensed under the MIT License:
 * http://www.opensource.org/licenses/mit-license.php
 * 
 *  5 December 2006
 *   Select option(s) by value with 'selectOptions'
 *   Based on code by Mathias Bank (http://www.mathias-bank.de)
 */
 
/*
 * Adds (single/multiple) options to a select box (or series of select boxes)
 *
 * @name     addOption
 * @author   Sam Collett (http://www.texotela.co.uk)
 * @example  $("#myselect").addOption("Value", "Text"); // add single value (will be selected)
 *           $("#myselect").addOption("Value 2", "Text 2", false); // add single value (won't be selected)
 *           $("#myselect").addOption({"foo":"bar","bar":"baz"}, false); // add multiple values, but don't select
 *
 */
jQuery.fn.addOption = function()
{
        if(arguments.length == 0) return this;
        // select option when added? default is true
        var selectOption = true;
        // multiple items
        var multiple = false;
        if(typeof arguments[0] == "object")
        {
                multiple = true;
                var items = arguments[0];
        }
        if(arguments.length >= 2)
        {
                if(typeof arguments[1] == "boolean") selectOption = arguments[1];
                else if(typeof arguments[2] == "boolean") selectOption = arguments[2];
                if(!multiple)
                {
                        var value = arguments[0];
                        var text = arguments[1];
                }
        }
        this.each(
                function()
                {
                        if(this.nodeName.toLowerCase() != "select") return;
                        if(multiple)
                        {
                                for(var v in items)
                                {
                                        jQuery(this).addOption(v, items[v], selectOption);
                                }
                        }
                        else
                        {
                                var option = document.createElement("option");
                                option.value = value;
                                option.text = text;
                                this.options.add(option);
                        }
                        if(selectOption)
                        {
                                this.options[this.options.length-1].selected = true;
                        }
                }
        )
        return this;
}

/*
 * Removes an option (by value or index) from a select box (or series of select boxes)
 *
 * @name     removeOption
 * @author   Sam Collett (http://www.texotela.co.uk)
 * @example  jQuery("#myselect").removeOption("Value"); // remove by value
 *           jQuery("#myselect").removeOption(0); // remove by index
 *
 */
jQuery.fn.removeOption = function()
{
        if(arguments.length == 0) return this;
        if(typeof arguments[0] == "string") var value = arguments[0];
        else if(typeof arguments[0] == "number") var index = arguments[0];
        else return this;
        this.each(
                function()
                {
                        if(this.nodeName.toLowerCase() != "select") return;
                        if(value)
                        {
                                var optionsLength = this.options.length;
                                for(var i=optionsLength-1; i>=0; i--)
                                {
                                        if(this.options[i].value == value)
                                        {
                                                this.options[i] = null;
                                        }
                                }
                        }
                        else
                        {
                                this.remove(index);
                        }
                }
        )
        return this;
}

/*
 * Sort options (ascending or descending) in a select box (or series of select boxes)
 *
 * @name     sortOptions
 * @author   Sam Collett (http://www.texotela.co.uk)
 * @param    ascending   Sort ascending (true/undefined), or descending (false)
 * @example  // ascending
 *           jQuery("#myselect").sortOptions(); // or jQuery("#myselect").sortOptions(true);
 *           // descending
 *           jQuery("#myselect").sortOptions(false);
 *
 */
jQuery.fn.sortOptions = function(ascending)
{
        this.each(
                function()
                {
                        if(this.nodeName.toLowerCase() != "select") return;
                        // default sort is ascending if parameter is undefined
                        ascending = typeof ascending == "undefined" ? true : ascending;
                        // get number of options
                        var optionsLength = this.options.length;
                        // create an array for sorting
                        var sortArray = [];
                        // loop through options, adding to sort array
                        for(var i = 0; i<optionsLength; i++)
                        {
                                sortArray[i] =
                                {
                                        value: this.options[i].value,
                                        text: this.options[i].text
                                };
                        }
                        // sort items in array
                        sortArray.sort(
                                function(option1, option2)
                                {
                                        // option text is made lowercase for case insensitive sorting
                                        option1text = option1.text.toLowerCase();
                                        option2text = option2.text.toLowerCase();
                                        // if options are the same, no sorting is needed
                                        if(option1text == option2text) return 0;
                                        if(ascending)
                                        {
                                                return option1text < option2text ? -1 : 1;
                                        }
                                        else
                                        {
                                                return option1text > option2text ? -1 : 1;
                                        }
                                }
                        );
                        // change the options to match the sort array
                        for(var i = 0; i<optionsLength; i++)
                        {
                                this.options[i].text = sortArray[i].text;
                                this.options[i].value = sortArray[i].value;
                        }
                }
        )
        return this;
}
/*
 * Selects an option by name
 *
 * @name     selectOptionsByName
 * @author   Mathias Bank (http://www.mathias-bank.de), original function
 * @author   Sam Collett (http://www.texotela.co.uk), addition of regular expression matching
 * @param    value specifies, which options should be selected
 *           can be a string or regular expression
 * @example  jQuery("#myselect").selectOptions("val1"); // with the value 'val1'
 * @example  jQuery("#myselect").selectOptions(/^val/i); // with the value starting with 'val', case insensitive
 *
 */
jQuery.fn.selectOptionsByName = function(value)
{
        var valueType = typeof value;
        // has to be a string or regular expression (object in IE, function in Firefox)
        if(valueType != "string" && valueType != "function" && valueType != "object") return this;
        this.each(
                function()
                {
                        if(this.nodeName.toLowerCase() != "select") return this;
                        
                        // get number of options
                        var optionsLength = this.options.length;
                        
                        for(var i = 0; i<optionsLength; i++)
                        {
                                if(value.constructor == RegExp)
                                {
                                        if (this.options[i].innerHTML.match(value))
                                        {
                                                this.options[i].selected = true;
                                        }
                                }
                                else
                                {
                                        if (this.options[i].innerHTML == value)
                                        {
                                                this.options[i].selected = true;
                                        }
                                }
                        }
                }
        )
        return this;
}
/*
 * Selects an option by value
 *
 * @name     selectOptionsByValue
 * @author   Mathias Bank (http://www.mathias-bank.de), original function
 * @author   Sam Collett (http://www.texotela.co.uk), addition of regular expression matching
 * @param    value specifies, which options should be selected
 *           can be a string or regular expression
 * @example  jQuery("#myselect").selectOptions("val1"); // with the value 'val1'
 * @example  jQuery("#myselect").selectOptions(/^val/i); // with the value starting with 'val', case insensitive
 *
 */
jQuery.fn.selectOptionsByValue = function(value)
{
        var valueType = typeof value;
        // has to be a string or regular expression (object in IE, function in Firefox)
        if(valueType != "string" && valueType != "function" && valueType != "object") return this;
        this.each(
                function()
                {
                        if(this.nodeName.toLowerCase() != "select") return this;
                        
                        // get number of options
                        var optionsLength = this.options.length;
                        
                        for(var i = 0; i<optionsLength; i++)
                        {
                                if(value.constructor == RegExp)
                                {
                                        if (this.options[i].value.match(value))
                                        {
                                                this.options[i].selected = true;
                                        }
                                }
                                else
                                {
                                        if (this.options[i].value == value)
                                        {
                                                this.options[i].selected = true;
                                        }
                                }
                        }
                }
        )
        return this;
}
/*
 * Selects an option by value
 *
 * @name     selectOptions
 * @author   Mathias Bank (http://www.mathias-bank.de), original function
 * @author   Sam Collett (http://www.texotela.co.uk), addition of regular expression matching
 * @param    value specifies, which options should be selected
 *           can be a string or regular expression
 * @example  jQuery("#myselect").selectOptions("val1"); // with the value 'val1'
 * @example  jQuery("#myselect").selectOptions(/^val/i); // with the value starting with 'val', case insensitive
 *
 */
jQuery.fn.selectOptions = jQuery.fn.selectOptionsByValue;
/*
 * Retrieves Selected options
 *
 * @name     selectedOptionsByName
 * @author   Petko D. Petkov | pdp (architect) (http://www.gnucitizen.org)
 * @example  jQuery("#myselect").selectedOptions();
 *
 */
jQuery.fn.selectedOptionsByName = function() {
        var options = new Array();
        
        this.each(
                function()
                {
                        if(this.nodeName.toLowerCase() != "select") return this;
                        
                        // get number of options
                        var optionsLength = this.options.length;
                        
                        for(var i = 0; i<optionsLength; i++)
                        {
                                if (this.options[i].selected)
                                        options.push(this.options[i].innerHTML);
                        }
                }
        )
        
        return options;
}
/*
 * Retrieves Selected options
 *
 * @name     selectedOptionsByValue
 * @author   Petko D. Petkov | pdp (architect) (http://www.gnucitizen.org)
 * @example  jQuery("#myselect").selectedOptions();
 *
 */
jQuery.fn.selectedOptionsByValue = function() {
        var options = new Array();
        
        this.each(
                function()
                {
                        if(this.nodeName.toLowerCase() != "select") return this;
                        
                        // get number of options
                        var optionsLength = this.options.length;
                        
                        for(var i = 0; i<optionsLength; i++)
                        {
                                if (this.options[i].selected)
                                        options.push(this.options[i].value);
                        }
                }
        )
        
        return options;
}
/*
 * Retrieves Selected options
 *
 * @name     selectedOptions
 * @author   Petko D. Petkov | pdp (architect) (http://www.gnucitizen.org)
 * @example  jQuery("#myselect").selectedOptions();
 *
 */
jQuery.fn.selectedOptions = jQuery.fn.selectedOptionsByValue;
/*
 * Retrieves Selected options
 *
 * @name     selectedOptionsPairs
 * @author   Petko D. Petkov | pdp (architect) (http://www.gnucitizen.org)
 * @example  jQuery("#myselect").selectedOptions();
 *
 */
jQuery.fn.selectedOptionsPairs = function() {
        var options = new Array();
        
        this.each(
                function()
                {
                        if(this.nodeName.toLowerCase() != "select") return this;
                        
                        // get number of options
                        var optionsLength = this.options.length;
                        
                        for(var i = 0; i<optionsLength; i++)
                        {
                                if (this.options[i].selected)
                                        options.push({name: this.options[i].innerHTML, value: this.options[i].value});
                        }
                }
        )
        
        return options;
}
